package com.koron.car.web.applycar.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.date.DateTime;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.car.config.Constants;
import com.koron.car.web.applycar.bean.entity.DriverRecord;
import com.koron.car.web.applycar.bean.entity.DriverSchedule;
import com.koron.car.web.applycar.bean.query.DriverRecordQuery;
import com.koron.car.web.applycar.bean.query.StatisticalReportQuery;
import com.koron.car.web.applycar.bean.vo.CarApplyVO;
import com.koron.car.web.applycar.bean.vo.CarStatisticalReportVO;
import com.koron.car.web.applycar.bean.vo.DriverRecordVO;
import com.koron.car.web.applycar.bean.vo.DriverStatisticalReportVO;
import com.koron.car.web.applycar.feign.SystemFeignService;
import com.koron.car.web.applycar.mapper.DriverRecordMapper;
import com.koron.car.web.applycar.mapper.DriverScheduleMapper;
import com.koron.car.web.applycar.service.CarApplyService;
import com.koron.car.web.applycar.service.DriverRecordService;
import com.koron.car.web.applycar.service.DriverScheduleService;
import com.koron.car.web.costregister.bean.entity.CostRegister;
import com.koron.car.web.costregister.mapper.CostRegisterMapper;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * (DriverRecord)表服务实现类
 *
 * @author twcao
 * @since 2022-03-09 10:37:10
 */
@Slf4j
@Service
public class DriverRecordServiceImpl implements DriverRecordService {

    @Autowired
    private SystemFeignService systemFeignService;

    @Autowired
    private DriverScheduleService driverScheduleService;

    @Autowired
    private CarApplyService carApplyService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    @TaskAnnotation("queryById")
    public DriverRecord queryById(SessionFactory factory, String id) {
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        return mapper.queryById(id);
    }

    /**
     * 根据申请id查询行驶记录
     *
     * @param factory
     * @param applyId
     * @return
     */
    @Override
    @TaskAnnotation("getByApplyId")
    public List<DriverRecord> getByApplyId(SessionFactory factory, String applyId) {
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        return mapper.getByApplyId(applyId);
    }

    /**
     * 查询多条数据
     *
     * @param query 查询记录
     * @return 对象列表
     */
    @Override
    @TaskAnnotation("queryList")
    public List<DriverRecordVO> queryList(SessionFactory factory, DriverRecordQuery query) {
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        return mapper.queryList(query);
    }

    /**
     * 新增数据
     *
     * @param record 实例对象
     * @return 实例对象
     */
    @Override
    @TaskAnnotation("insert")
    public synchronized DriverRecord insert(SessionFactory factory, DriverRecord record) {
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        Assert.notNull(record, "行驶记录不能为空");
        Assert.hasText(record.getApplyId(), "申请id不能为空");
        Assert.hasText(record.getScheduleId(), "调度id不能为空");
        if (StringUtils.isNotBlank(record.getDriverId())) {
            EamUser eamUser = ThreadLocalContext.get();
            // 如果不是租赁司机，则检查行驶记录是否填完了，禁止有行驶记录没有填完，再新增行驶记录的行为
            DriverRecord driverRecord = mapper.drivingRecord(record.getApplyId(), eamUser.getAccount());
            Assert.isNull(driverRecord, record.getDriverName() + "有未提交的行驶记录");
        }
        record.setId(CodeTools.getCode32());
        // 默认已经提交了
        record.setState(StringUtils.isBlank(record.getState()) ? String.valueOf(Constants.YesOrNo.NO) : record.getState());
        record.setParkFee(record.getParkFee() == null ? 0.0 : record.getParkFee());
        record.setOtherFee(record.getOtherFee() == null ? 0.0 : record.getOtherFee());
        mapper.insert(record);
        calculateSchedule(factory, record.getApplyId());
        return record;
    }

    /**
     * 修改数据
     *
     * @param record 实例对象
     * @return 实例对象
     */
    @Override
    @TaskAnnotation("update")
    public DriverRecord update(SessionFactory factory, DriverRecord record) {
        Assert.hasText(record.getApplyId(), "申请id不能为空");
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        // todo 前端应该传state 来判断当前记录是不是提交的 state = '0'
        record.setState(StringUtils.isBlank(record.getState()) ? String.valueOf(Constants.YesOrNo.NO) : record.getState());
        record.setParkFee(record.getParkFee() == null ? 0.0 : record.getParkFee());
        record.setOtherFee(record.getOtherFee() == null ? 0.0 : record.getOtherFee());
        mapper.update(record);
        calculateSchedule(factory, record.getApplyId());
        return queryById(factory, record.getId());
    }

    @Override
    @TaskAnnotation("submitDriverRecordFee")
    public void submitDriverRecordFee(SessionFactory factory, String applyId) {
        CostRegisterMapper costRegisterMapper = factory.getMapper(CostRegisterMapper.class);
        DriverRecordMapper driverRecordMapper = factory.getMapper(DriverRecordMapper.class);
        List<CostRegister> costRegisterList = new ArrayList<>();
        DriverRecordService driverRecordService = SpringUtils.getBean(this.getClass());
        List<DriverRecord> driverRecordList = driverRecordService.getByApplyId(factory, applyId);
        DriverSchedule driverSchedule = driverScheduleService.getByApplyId(factory, applyId);
        CarApplyVO carApplyVO = carApplyService.queryById(factory,applyId);
        Assert.notNull(driverRecordList,"当前申请订单调度信息不存在！");
        if (CollectionUtils.isNotEmpty(driverRecordList)) {

            driverRecordList.stream().forEach(record -> {
                // 停车费
                if (record.getParkFee() > 0) {
                    CostRegister parkCostRegister = new CostRegister();
                    parkCostRegister.setId(CodeTools.getCode32());
                    parkCostRegister.setDriverId(record.getDriverId());
                    parkCostRegister.setCostType(Constants.FeeType.PARKFEE);
                    parkCostRegister.setCost(record.getParkFee());
                    parkCostRegister.setApplyId(record.getApplyId());
                    parkCostRegister.setState(Constants.FeeState.FINISH);
                    parkCostRegister.setCarId(driverSchedule.getCarId());
                    parkCostRegister.setLicPlateNum(driverSchedule.getLicPlateNum());
                    parkCostRegister.setMotorcade(driverSchedule.getMotorcade());
                    parkCostRegister.setDriverName(record.getDriverName());
                    parkCostRegister.setApplyCode(carApplyVO.getCode());
                    parkCostRegister.setStartTime(new Date());
                    setCostProperty(parkCostRegister);
                    costRegisterList.add(parkCostRegister);
                }
                // 维修保养费
                if (record.getOtherFee() > 0) {
                    CostRegister otherCostRegister = new CostRegister();
                    otherCostRegister.setId(CodeTools.getCode32());
                    otherCostRegister.setDriverId(record.getDriverId());
                    otherCostRegister.setCostType(Constants.FeeType.MATAINFEE);
                    otherCostRegister.setCost(record.getOtherFee());
                    otherCostRegister.setApplyId(record.getApplyId());
                    otherCostRegister.setState(Constants.FeeState.FINISH);
                    otherCostRegister.setCarId(driverSchedule.getCarId());
                    otherCostRegister.setLicPlateNum(driverSchedule.getLicPlateNum());
                    otherCostRegister.setMotorcade(driverSchedule.getMotorcade());
                    otherCostRegister.setDriverName(record.getDriverName());
                    otherCostRegister.setApplyCode(carApplyVO.getCode());
                    otherCostRegister.setStartTime(new Date());
                    setCostProperty(otherCostRegister);
                    costRegisterList.add(otherCostRegister);
                }
                // 设置记录状态为已经完成
                record.setState(String.valueOf(Constants.YesOrNo.YES));
                driverRecordMapper.update(record);
            });
        }
        // 同时将记录插入到费用表中
        if (CollectionUtils.isNotEmpty(costRegisterList)) {
            costRegisterMapper.insertBatch(costRegisterList);
        }
    }

    public void setCostProperty(CostRegister costRegister){
        EamUser eamUser = ThreadLocalContext.get();
        // 获取当前登录用户作为操作用户
        costRegister.setCreateBy(eamUser.getNamePy());
        costRegister.setCreateByName(eamUser.getName());
        costRegister.setCreateTime(DateTime.now());
        costRegister.setUpdateBy(eamUser.getNamePy());
        costRegister.setUpdateByName(eamUser.getName());
        costRegister.setUpdateTime(DateTime.now());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    @TaskAnnotation("deleteById")
    public boolean deleteById(SessionFactory factory, String id) {
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        DriverRecordVO driverRecordVO = mapper.getById(id);
        if (Objects.nonNull(driverRecordVO)) {
            return mapper.deleteById(id) > 0;
        }
        return false;
    }


    /**
     * 根据行驶信息明细，计算回车登记信息（实际开始时间、实际结束时间、本单开始里程、本单结束里程）,并完成回车登记赋值
     * 先后顺序，以更新时间为准:
     */
    @Override
    public void calculateSchedule(SessionFactory factory, String applyId) {
        if (StringUtils.isBlank(applyId)) {
            return;
        }
        DriverRecordMapper mapper = factory.getMapper(DriverRecordMapper.class);
        List<DriverRecord> records = mapper.getByApplyId(applyId);
        // 如果没有记录行驶信息，返回即可
        if (CollectionUtils.isEmpty(records)) {
            return;
        }
        // 1、根据行驶记录，计算回车登记信息
        int length = records.size();
        // 实际开始时间
        Date factStartTime = records.get(0).getStartTime();
        // 用车起始累计里程
        Double startMileage = records.get(0).getStartMileage();
        // 实际结束时间
        Date factEndTime = records.get(length - 1).getEndTime();
        // 用车结束累计里程
        Double endMileage = records.get(length - 1).getEndMileage();
        // 2、设置回车登记信息
        DriverScheduleMapper scheduleMapper = factory.getMapper(DriverScheduleMapper.class);
        DriverSchedule schedule = scheduleMapper.getByApplyId(applyId);
        schedule.setFactStartTime(factStartTime);
        schedule.setFactEndTime(factEndTime);
        schedule.setStartMileage(startMileage);
        schedule.setEndMileage(endMileage);
        scheduleMapper.update(schedule);
    }

    @Override
    @TaskAnnotation("queryDriverStaList")
    public List<DriverStatisticalReportVO> queryDriverStaList(SessionFactory factory, StatisticalReportQuery query) {
        DriverRecordMapper recordMapper = factory.getMapper(DriverRecordMapper.class);
//        String time = String.valueOf(new SimpleDateFormat("yyyy-MM").format(new Date()));
//        if (query.getStatisticalBeginMonth() == null && query.getStatisticalEndMonth() == null) {
//            query.setStatisticalBeginMonth(time);
//            query.setStatisticalEndMonth(time);
//        }
        List<DriverStatisticalReportVO> reportVOList = recordMapper.queryDriverStaList(query);
        if (CollectionUtils.isNotEmpty(reportVOList)) {
            reportVOList.stream().forEach(driverStatisticalReportVO -> {
                if (StringUtils.isNotBlank(query.getStatisticalBeginMonth()) && StringUtils.isNotBlank(query.getStatisticalEndMonth())) {
                    driverStatisticalReportVO.setMonth(query.getStatisticalBeginMonth() + "至" + query.getStatisticalEndMonth());
                } else {
                    driverStatisticalReportVO.setMonth("-");
                }
            });
        }
        return reportVOList;
    }

    @Override
    @TaskAnnotation("queryCarStaList")
    public List<CarStatisticalReportVO> queryCarStaList(SessionFactory factory, StatisticalReportQuery query) {
        DriverRecordMapper recordMapper = factory.getMapper(DriverRecordMapper.class);
//        String time = String.valueOf(new SimpleDateFormat("yyyy-MM").format(new Date()));
//        if (query.getStatisticalBeginMonth() == null && query.getStatisticalEndMonth() == null) {
//            query.setStatisticalBeginMonth(time);
//            query.setStatisticalEndMonth(time);
//        }
        List<CarStatisticalReportVO> reportVOList = recordMapper.queryCarStaList(query);
        if (reportVOList!=null) {
            reportVOList.stream().forEach(carStatisticalReportVO -> {
                if (StringUtils.isNotBlank(query.getStatisticalBeginMonth()) && StringUtils.isNotBlank(query.getStatisticalEndMonth())) {
                    carStatisticalReportVO.setMonth(query.getStatisticalBeginMonth() + "至" + query.getStatisticalEndMonth());
                } else {
                    carStatisticalReportVO.setMonth("-");
                }
            });
        }
        return reportVOList;
    }


    @Override
    @TaskAnnotation("calCarNum")
    public void calCarNum(SessionFactory factory, StatisticalReportQuery query, HttpServletResponse response) {
        DriverRecordMapper recordMapper = factory.getMapper(DriverRecordMapper.class);
        AtomicReference<String> month = new AtomicReference<>("");
        List<CarStatisticalReportVO> reportVOList = recordMapper.queryCarStaList(query);
        if(reportVOList!=null) {
            reportVOList.stream().forEach(carStatisticalReportVO -> {
                if (StringUtils.isNotBlank(query.getStatisticalBeginMonth()) && StringUtils.isNotBlank(query.getStatisticalEndMonth())) {
                    month.set(query.getStatisticalBeginMonth() + "至" + query.getStatisticalEndMonth());
                    carStatisticalReportVO.setMonth(month.get());
                } else {
                    carStatisticalReportVO.setMonth("-");
                }
            });
        }
        Integer remaining = recordMapper.countRemaining();
        List<Map<String, Long>> list = recordMapper.queryCarModel();
        Map<String, Object> map = new HashMap<>();
        String dictionary = "1498848931042430976";
        String appid = "0";
        List result = (List) systemFeignService.getDetailsByDictionaryAndAppId(dictionary, appid).getData();
        result.stream().forEach(element -> {
            LinkedHashMap linkedHashMap = (LinkedHashMap) element;
            String key = (String) linkedHashMap.get("key");
            map.put(key, 0L);
        });
        Long sum = 0L;
        for (Map<String, Long> carMap : list) {
            map.put(String.valueOf(carMap.get("model")), carMap.get("modelNum"));
            sum += carMap.get("modelNum");
        }
        map.put("list", reportVOList == null ? new ArrayList<>() : reportVOList);
        map.put("sum", sum);
        map.put("remaining", remaining);
        map.put("title",month.get() + "车辆行程管理信息");
        map.put("beginMonth", query.getStatisticalBeginMonth().split("-")[1]);
        map.put("endMonth", query.getStatisticalEndMonth().split("-")[1]);
        map.put("totalMonthBeginDistance", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getMonthBeginDistance())).reduce(0.0,Double::sum));
        map.put("totalMonthEndDistance", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getMonthEndDistance())).reduce(0.0,Double::sum));
        map.put("sumTotalDistance", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getTotalDistance())).reduce(0.0,Double::sum));
        map.put("totalOil", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getOil())).reduce(0.0,Double::sum));
        map.put("totalOilCost", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getOilCost())).reduce(0.0,Double::sum) / reportVOList.size());
        map.put("totalMatainFee", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getMatainFee())).reduce(0.0,Double::sum));
        map.put("totalTollFee", reportVOList.stream().map(carStatisticalReportVO -> Double.valueOf(carStatisticalReportVO.getTollFee())).reduce(0.0,Double::sum));
        log.info(map.toString());
        //获取模板的路径  SpringBoot项目获取根目录的方式
        try {
            Workbook workbook = WorkbookFactory.create(new ClassPathResource("excelTemplate/carStaTemplate.xls").getInputStream());
            //读取模板文件
            TemplateExportParams params = new TemplateExportParams();
            params.setTemplateWb(workbook);
            workbook = ExcelExportUtil.exportExcel(params, map);
            //导出的文件名称
            String filename = month.get() + "车辆行程管理信息.xls";
            //设置文件的打开方式和mime类型
            ServletOutputStream outputStream = response.getOutputStream();
            filename = URLEncoder.encode(filename, "UTF-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.ms-excel; charset=UTF-8");
            response.setHeader("Content-disposition", "attachment;filename="+filename+";"+"filename*=utf-8''"+filename);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            workbook.write(byteArrayOutputStream);
            response.setHeader("Content-Length", "" + byteArrayOutputStream.size());
            workbook.write(outputStream);
            outputStream.close();
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }

    }
}
